<template>
    <el-card class="box-card">
      <div slot="header" class="clearfix">
        <span>更换头像</span>
      </div>
      <div>
        <!-- 图片，用来展示用户选择的头像 -->
        <img v-if="!avatar" class="the_img" src="../../assets/images/avatar.jpg" alt="" />
        <img v-else class="the_img" :src="avatar" alt="" />

        <!-- 按钮区域 -->
        <div class="btn-box">
          <input type="file" accept="image/*" style="display: none" ref="iptRef" @change="onFileChange" />
          <el-button type="primary" icon="el-icon-plus" @click="chooseImg">选择图片</el-button>
          <el-button type="success" icon="el-icon-upload" :disabled="avatar === ''" @click="uploadFn" >上传头像</el-button>
        </div>
      </div>
    </el-card>
  </template>

<script>
import { updateUserAvatarAPI } from '@/api'
export default {
  name: 'UserAvatar',
  data () {
    return {
      avatar: '' // 保存图片链接/base64字符串
    }
  },
  methods: {
    // 选择图片点击事件
    chooseImg () {
    // 目的：为了让input[tyoe = file]标签，让他再用JS代码来触发它的点击事件(导致它默认行为给一个文件选择窗口)
    // 原因：input[tyoe = file]标签是原生标签，样式不好改
      this.$refs.iptRef.click()
    },
    // 在选择框中选择图片后触发的改变事件
    onFileChange (e) { // e 原生事件对象
      const files = e.target.files // 拿到用户选择的文件数组
      if (files.length === 0) {
        // 证明刚刚文件选择窗口打开了，但是它是一个文件都没选择然后点击了确定关闭选择弹窗
        this.avatar = ''
      } else {
        // 证明它选择了文件(默认只能选一个，如果选择多个需要给input标签加额外原生属性)
        console.log(files[0])

        // 目标：选择的图片文件，要给到img标签上做纯前端的预览
        // 知识点：img标签的src值
        // * 只能是图片的"链接地址"(外链http://开头，图片文件相对路径)
        // * 或者是图片的base64字符串(而且字符串还必须是data:image/png;base64,图片转base64字符串)
        // 解决方案1：文件 -> 内存临时地址(这个地址只能在js内存里，不能发给后台)
        // 语法：URL.createObjectURL(文件)
        // 返回值：内存临时地址
        // this.avatar = URL.createObjectURL(files[0])

        // 解决方案2：文件 -> base64字符串(此字符串是可以发给后台的)
        // 1. 创建 FileReader 对象
        const fr = new FileReader()
        // 2. 调用 readAsDataURL 函数，读取文件内容
        fr.readAsDataURL(files[0])
        // 3. 监听 fr 的 onload 事件
        fr.onload = e => { // onload等待把文件读成base64字符串后会触发onload事件函数
          // 4. 通过 e.target.result 获取到读取的结果，值是字符串（base64 格式的字符串）并赋予给avatar
          this.avatar = e.target.result
        }
      }
    },
    // 上传头像点击事件
    async uploadFn () {
      const { data: res } = await updateUserAvatarAPI(this.avatar)
      if (res.code !== 0) return this.$message.error(res.message)
      // 更新头像成功
      this.$message.success(res.message)
      // 重新让vuex获取下最新的用户数据
      this.$store.dispatch('getUserInfoActions')
    }
  }
}
</script>

  <style lang="less" scoped>
  .btn-box {
    margin-top: 10px;
  }
  .preview {
    object-fit: cover;
  }
  .the_img{
      width: 350px;
      height: 350px;
  }
  </style>

<!-- 前端：
前提：
通过input[type=file]让用户选择文件，通过事件对象.target.files拿到用户选择的"文件对象"
预览：img标签的src属性的值(base64字符串/图片链接地址)

  情况l:文件转成图片base64字符串：new Fi1 eReader()
  给src属性赋予base64字符串（图片数据转base64字符串），特点以data:image/png;base64,开头

  情况2：文件转成图片链接地址：URL.createObjURL(文件)
  注意：它的地址只能在前端使用

  需求：把用户选择的文件发给后台保存在服务器上
  情况1：文件转成图片base64字符串，传递给后台
  情况2：用new FormData()表单数据直接装文件本身，直接传递给后台 -->

<!-- 后端返回图片链接地址的经验：
为何后端返回的图片地址是半截的？
原因：因为服务器的域名可能会来回变化，所以数据库里的地址只有相对路径
要求：前端请求此图片的时候，后端告诉你图片文件真身所在的服务器域名，前端自己拼接前缀 -->
